/**
 * 将wx相关api封装成Promise化
 * 消息通知以及向上(SDK,UI)层传递采用事件发布订阅机制
 */

 import {soketUrl} from './config'
 import {Event,constEventName} from './event'



const is_wx=typeof wx!==undefined  //是否在小程序内
const is_window=typeof window!==undefined

const Wo=require('./wx_promise')||{} //将wx apiPromise化

const MAX_RECONNECT_TIMES=10


let timer1=null,timer2=null //重连的定时器

const Socket={

   ws:null, 
   socket_options:null, //接口获取option
   reConnectStatus:false, //是否正在重连状态
   reConnectTime:0, //重连尝试的当前次数

   $connect:false, //标明是否是合理的断开连接 false表示合理，true表示不合理

   //wait_queue:[],   //未发送的消息暂存队列

   

   /**初始化*/
   async init(){
      /**api请求，可能还要包含token之内的*/
      this.socket_options={url:soketUrl,token:123} 

   /**初始化事件绑定 */

     /**设置readyState的状态值变化监听,但小程序不支持所以放弃 */

     /**设置发送消息的事件监听 */
     Event.$on(constEventName.message_client_send,Msg=>{
        this.sendMessage(Msg)
    })

    this.connect()

    /**mini/web的初始化 */
    if(is_wx){
        this.ws.onMessage(evt=>{
            var data=evt.data
            this.receiveMessage(data)
        })
        this.ws.onSocketError(res=>{
            if(this.$connect) this.reconnect()
            this.$connect=false
        })
        this.ws.onError(res=>{
            if(this.$connect) this.reconnect()
            this.$connect=false
        })

    }else{
        this.ws.onmessage=evt=>{
            /**接收消息类型 需要自定义协议  DataView*/
            var data=evt.data;
            this.receiveMessage(data)
        }
        this.ws.onerror=()=>{ //断线重连
    
        }

    }



   },

   /**连接 */
   connect(){
       /**protocols 子协议数组，[]里面可以按需加入token，这些 */
     this.ws =!is_wx?new WebSocket(this.socket_options.url,[this.socket_options.token]):Wo.connectSocket({url:this.socket_options.url,protocols:[this.socket_options.token]}).then(res=>{
         /**成功回调 */
     },res=>{ //失败回调
        this.reconnect()
     },res=>{ //完成的回调

     })
     
   },
   /**
    * 断线重连
    *  */
   reconnect(){
     clearInterval(timer1)
     /**
      * 
      */
     if(this.checkWsReady()) return
     if(this.reConnectStatus) return //已经在重连过程中
     if(is_wx) Wo.closeSocket()
    
     /**重连 */
     this.reConnectStatus=true
     clearTimeout(timer2)
     if(this.reConnectTime<MAX_RECONNECT_TIMES){
         timer2=setTimeout(()=>{
             this.connect()
             this.reConnectStatus=false
         },1000)
         this.reConnectTime++
     }


   },

   /**
    * 检查连接状态是否为ready,每次发送之前都需要确认
    * CLOSED:3 CLOSING:2 CONNECTING:0 OPEN:1
    * 如果带有Msg参数，则检查连接正常后直接发送
    *  */
   checkWsReady(Msg){
       if(this.ws&&(this.ws.readyState==1||this.ws.readyState==0)){
        if(this.ws.readyState==0){ //当连接状态处于CONNECTING,等待其状态变为1，再发送wait_queue队列

            timer1=setInterval(()=>{
                if(this.ws.readyState==1){
                    clearInterval(timer1)
                    /**发送暂存消息 */
                   Msg&&this.send(Msg)
                }
            })

        }else if(this.ws.readyState==1) Msg&&this.send(Msg)  
        return true
       } 
       /**如果是正在连接，则一并将其加入队列中 */
       else return false
   },

   /**
    * 发送消息
    * 需要先确认连接状态 
    *  */
   sendMessage(Msg){
     if(!this.checkWsReady(Msg)){
         /**通知上一层发送失败 */
        Event.$emit(constEventName.message_send_time_out,Msg)
        return
     }

   },

   /**
    * 单纯的消息发送(需要拼接Buffer/Protobuf)等格式，不做连接状态的检查
    * 需要处理header，body相关协议
    *  */
   send(Msg){
     Wo.sendSocketMessage({
         data:Msg, //可能需要转化
     }).then(res=>{ 
        console.log('发送成功')
     },res=>{
        console.log('发送失败') 
     })
   },

   /**接收消息
    * 事件向上广播
   */
   receiveMessage(res){
      console.log(res)
      /**需要区分消息是握手确认还是新消息 */
      Event.$emit(constEventName.message_send_success,res)

      Event.$emit(constEventName.message_new_received,res)
   },
   /**关闭连接 */
   close(){
       this.$connect=false
       if(is_wx) this.ws.closeSocket() 
       else  this.ws.close()
   }


}

module.exports=Socket

